﻿#include "QtEnvFind.h"
#include <QstandardPaths>
#include <QDebug>
#include <QDir>


#define AppLocation QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)


QtEnvFind::QtEnvFind(QObject* parent)
	:QObject(parent)
{
	//test:	找到可以遍历到		MinGW 11.2.0 (64-bit)	的文件目录：
#if 0
	for (int i = 0; i < 18; i++)
	{
		qInfo() << QStandardPaths::writableLocation(QStandardPaths::StandardLocation(i));
	}		//是第三个；

	qInfo() << QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
	//"C:/Users/李飞/AppData/Roaming/Microsoft/Windows/Start Menu/Programs"

#endif


	qInfo() << qtVersionList();		//QList("6.5.2")
	//设置当前版本：
	setQtVersion(qtVersionList().first());		//6.5.2

	qInfo() << qtCompilerList();	//QList("MinGW 11.2.0 (64-bit)", "MSVC 2019 (64-bit)")


}

//Qt的版本列表：
QStringList QtEnvFind::qtVersionList()
{
	QDir dir(AppLocation);
	
	auto list = dir.entryList(QStringList() << "Qt*");
			//entryList—— 根据参数的名称过滤器	返回目录中所有文件和目录的名称列表；
	if (list.isEmpty())
	{
		return QStringList();
	}

	//进入这个文件目录：	进入Qt目录中去:
	dir.cd(list.first());

	//保存文件路径：
	m_qtRoot = dir.path();

	//再进去一次：
	return dir.entryList(QDir::Filter::Dirs | QDir::Filter::NoDotAndDotDot/*没有点*/);

}


//Qt的编译套件列表：
QStringList QtEnvFind::qtCompilerList()
{
	QDir dir(m_qtRoot);
	if (!dir.cd(m_currentVersion))
	{
		qInfo() << "进入" << m_currentVersion << "目录失败";
	}

	return dir.entryList(QDir::Filter::Dirs | QDir::Filter::NoDotAndDotDot);
}

//设置Qt当前的版本：
void QtEnvFind::setQtVersion(const QString& version)
{
	if (m_currentVersion != version)
	{
		m_currentVersion = version;

		//如果版本发生改变，发送信号：
		emit CurrentQtVersionChanged(m_currentVersion);
	}
	
}

//获取qt当前版本：
QString QtEnvFind::GetqtVersion() const
{
	return m_currentVersion;	
}

//设置qt当前的编译套件：
void QtEnvFind::setQtBuildSuite(const QString& buildsuite)
{
	m_currentBuildSuite = buildsuite;
}
//获取qt当前的编译套件：
QString QtEnvFind::GetqtBuildSuite() const
{
	return m_currentBuildSuite;
}


//设置Qt可编程程序的文件：
void QtEnvFind::setExeFile(const QString& exe)
{
	m_exeFile = exe;
}


//获取Qt可编程程序的文件：
QString QtEnvFind::GetexeFile() const
{
	return m_exeFile;
}

//生成按钮函数：		生成	部署操作都在这里：
void QtEnvFind::Generate()
{
	//qInfo() << "1";

	//首先得获取到windeployqt这个命令：
		//首先要来到这个目录：C:\Users\李飞\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Qt\6.5.2\MSVC 2019 (64-bit)	：

	QDir dir(m_qtRoot + "/" + m_currentVersion + "/" + m_currentBuildSuite);
	//qInfo() << dir.path();


	//D:\Qt\QT_new\6.5.2\mingw_64\bin
	
	//获取套件目录下面的所有文件：
	auto files = dir.entryList(QDir::Filter::Files);
	if (files.isEmpty())
	{
		qWarning("获取编译套件目录上面的快捷方式失败");
		return;
	}

	//把第一个快捷方式（套件目录下面的文件都是程序的快捷打开方式）拿出来：	里面有四个快捷打开方式，都是在同一个根目录的：
	QFileInfo info(dir.path() + "/" + files.first());
	//qInfo() << info.symLinkTarget();						//打开的快捷方式在哪里生成		"D:/Qt/QT_new/6.5.2/mingw_64/bin/assistant.exe"
	//qInfo() << QFileInfo(info.symLinkTarget()).path();	//只要快捷方式的路径			"D:/Qt/QT_new/6.5.2/mingw_64/bin"
	
	//获取快捷方式指向的文件所在的目录：
	QString binPath = QFileInfo(info.symLinkTarget()).path();


	//设置应用程序的当前环境变量：
	const char*  path = QString(getenv("PATH") + setEnvPath(binPath)).toLocal8Bit().data();
	putenv(path);
	//qInfo() << path;





	//执行使用		windeployqt这个命令		有两种方式：
#if 0
	//1.使用c语言的方式：				没有debug的库，所以用release库来实现：
	const char* cmd = QString(binPath + "/" + "windeployqt.exe " +
		m_exeFile).toLocal8Bit().data();
	//qInfo() << QString(binPath + "/" + "windeployqt.exe " + m_exeFile) << cmd;
	system(cmd);

#else

	//2.使用Qt提供的方法：
		//1.使用阻塞的方式：	窗口都动不了；
	#if 0
		QProcess process;
	
		process.start(binPath + "/" + "windeployqt.exe ",		//启动的程序
			{ m_exeFile }									//隐式的构造		要启动的参数；
		);
	
		//等待开始：
		process.waitForStarted();
		//等待完成：
		process.waitForFinished();
	
		//查看输出的结果：
		auto retu = process.readAllStandardOutput();	//查看向标准输入输出的内容
		qInfo() << QString(retu);
	#else
		//直接使用信号与槽，不会阻塞：
		process = new QProcess(this);

		//看结果		信号与槽：
		connect(process, &QProcess::finished, this, [=]()
			{
				auto retu = process->readAllStandardOutput();	//查看向标准输入输出的内容
				qInfo() << QString(retu);
			});


		process->start(binPath + "/" + "windeployqt.exe ",		//启动的程序
			{ m_exeFile }									//隐式的构造		要启动的参数；
		);

		
	#endif



	
#endif


	//Cannot find Visual Studio installation directory, VCINSTALLDIR is not set.
	//这个问题，只是在配置msvc的时候能出现的，配置msvc还需要vs的	 vcvarsall.bat	数据包；
}

//测试按钮函数：
void QtEnvFind::TestApp()
{
	//qInfo() << 1;
	/*
	这是分离的方法，类似于多线程的一个守护线程，当启动	startDetached	这个程序之后，它就与我们的这个程序没关系了
	这样会安全好一点，		其他的方法可能没有关掉释放掉窗口，原来的自己的窗口就使用不了；
	QProcess::startDetached(qint64 *pid = nullptr):
		在一个新进程中启动由setProgram()设置的程序，并使用由setargarguments()设置的参数，并与之分离。成功时返回true;否则返回false。如果调用进程退出，分离的进程将不受影响地继续运行
	*/

	auto detached = QProcess::startDetached(m_exeFile);
	qInfo() << detached;

	emit TestAppFinished(detached);


}

void QtEnvFind::AboutApp()
{
	//qInfo() << "about";

	//显示关于的	新窗口：
	aboutwidget = new AboutWidget;
	aboutwidget->show();
}



QString QtEnvFind::setEnvPath(const QString& path)
{
	QFile file(path + "/" + "qtenv2.bat");
	if (!file.open(QIODevice::ReadOnly))
	{
		qWarning("open qtenv2.bat failed");
		return QString();
	}


	QString ret;
	while (file.atEnd())
	{
		QString line = file.readLine();
		if (line.indexOf("PATH") != -1)
		{
			//获取这个行的字符串的中间元素：第九个元素往后；删除后面的"%PATH%"之后的部分：
			ret = line.mid(9).remove("%PATH%").trimmed();

			break;
		}
	}


	return QString();
}

